#!/usr/bin/env python3
"""
企业级Git分支管理工具
简化Git Flow工作流的常用操作
"""

import argparse
import subprocess
import sys
import os
import re
from typing import List, Optional, Tuple


class GitFlowHelper:
    def __init__(self):
        self.current_dir = os.getcwd()
        
        # Conventional Commits正则表达式
        self.COMMIT_PATTERN = re.compile(
            r'^(feat|fix|docs|style|refactor|perf|test|chore|build|ci|revert)(\(.+\))?: .{1,50}(\n\n.*)?$'
        )
        
        # 类型描述
        self.TYPE_DESCRIPTIONS = {
            'feat': '新功能',
            'fix': '修复bug',
            'docs': '文档更新',
            'style': '代码格式化（不影响功能）',
            'refactor': '重构（既不是新功能也不是修复）',
            'perf': '性能优化',
            'test': '添加或修改测试',
            'chore': '构建过程或辅助工具的变动',
            'build': '构建系统或外部依赖的变更',
            'ci': 'CI配置文件和脚本的变更',
            'revert': '回滚之前的提交'
        }
        
    def run_command(self, command: List[str], check: bool = True) -> subprocess.CompletedProcess:
        """执行shell命令"""
        try:
            result = subprocess.run(
                command, 
                cwd=self.current_dir, 
                capture_output=True, 
                text=True,
                check=check
            )
            return result
        except subprocess.CalledProcessError as e:
            print(f"命令执行失败: {' '.join(command)}")
            print(f"错误信息: {e.stderr}")
            raise e
    
    def get_current_branch(self) -> str:
        """获取当前分支名"""
        try:
            result = self.run_command(["git", "branch", "--show-current"])
            return result.stdout.strip()
        except subprocess.CalledProcessError:
            # 如果--show-current不支持，使用其他方法
            result = self.run_command(["git", "rev-parse", "--abbrev-ref", "HEAD"])
            return result.stdout.strip()
    
    def is_branch_exists(self, branch_name: str) -> bool:
        """检查分支是否存在"""
        try:
            result = self.run_command(["git", "branch", "-a"], check=False)
            return branch_name in result.stdout
        except Exception:
            return False
    
    def create_feature_branch(self, feature_name: str) -> None:
        """创建功能分支"""
        branch_name = f"feature/{feature_name}"
        print(f"创建功能分支: {branch_name}")
        
        # 确保在develop分支上
        self.run_command(["git", "checkout", "develop"])
        self.run_command(["git", "pull", "origin", "develop"])
        
        # 创建并切换到新分支
        self.run_command(["git", "checkout", "-b", branch_name])
        print(f"已创建并切换到分支: {branch_name}")
    
    def finish_feature_branch(self, feature_name: str) -> None:
        """完成功能分支，合并到develop"""
        branch_name = f"feature/{feature_name}"
        current_branch = self.get_current_branch()
        
        if current_branch != branch_name:
            self.run_command(["git", "checkout", branch_name])
        
        # 确保代码是最新的
        self.run_command(["git", "pull", "origin", branch_name])
        
        # 切换到develop分支
        self.run_command(["git", "checkout", "develop"])
        self.run_command(["git", "pull", "origin", "develop"])
        
        # 合并feature分支
        self.run_command(["git", "merge", "--no-ff", branch_name])
        self.run_command(["git", "push", "origin", "develop"])
        
        # 删除feature分支
        self.run_command(["git", "branch", "-d", branch_name])
        print(f"已合并 {branch_name} 到 develop 并删除本地分支")
    
    def create_release_branch(self, version: str) -> None:
        """创建发布分支"""
        branch_name = f"release/{version}"
        print(f"创建发布分支: {branch_name}")
        
        # 确保在develop分支上
        self.run_command(["git", "checkout", "develop"])
        self.run_command(["git", "pull", "origin", "develop"])
        
        # 创建并切换到新分支
        self.run_command(["git", "checkout", "-b", branch_name])
        print(f"已创建并切换到分支: {branch_name}")
    
    def finish_release_branch(self, version: str) -> None:
        """完成发布分支，合并到master和develop"""
        branch_name = f"release/{version}"
        current_branch = self.get_current_branch()
        
        if current_branch != branch_name:
            self.run_command(["git", "checkout", branch_name])
        
        # 确保代码是最新的
        self.run_command(["git", "pull", "origin", branch_name])
        
        # 合并到master
        self.run_command(["git", "checkout", "master"])
        self.run_command(["git", "pull", "origin", "master"])
        self.run_command(["git", "merge", "--no-ff", branch_name])
        
        # 创建标签
        self.run_command(["git", "tag", "-a", f"v{version}", "-m", f"Release version {version}"])
        
        # 推送master和标签
        self.run_command(["git", "push", "origin", "master"])
        self.run_command(["git", "push", "origin", f"v{version}"])
        
        # 合并回develop
        self.run_command(["git", "checkout", "develop"])
        self.run_command(["git", "pull", "origin", "develop"])
        self.run_command(["git", "merge", "--no-ff", branch_name])
        self.run_command(["git", "push", "origin", "develop"])
        
        # 删除release分支
        self.run_command(["git", "branch", "-d", branch_name])
        print(f"已发布版本 {version} 并删除本地分支")
    
    def create_hotfix_branch(self, hotfix_name: str) -> None:
        """创建热修复分支"""
        branch_name = f"hotfix/{hotfix_name}"
        print(f"创建热修复分支: {branch_name}")
        
        # 确保在master分支上
        self.run_command(["git", "checkout", "master"])
        self.run_command(["git", "pull", "origin", "master"])
        
        # 创建并切换到新分支
        self.run_command(["git", "checkout", "-b", branch_name])
        print(f"已创建并切换到分支: {branch_name}")
    
    def finish_hotfix_branch(self, hotfix_name: str, version: Optional[str] = None) -> None:
        """完成热修复分支，合并到master和develop"""
        branch_name = f"hotfix/{hotfix_name}"
        current_branch = self.get_current_branch()
        
        if current_branch != branch_name:
            self.run_command(["git", "checkout", branch_name])
        
        # 确保代码是最新的
        self.run_command(["git", "pull", "origin", branch_name])
        
        # 合并到master
        self.run_command(["git", "checkout", "master"])
        self.run_command(["git", "pull", "origin", "master"])
        self.run_command(["git", "merge", "--no-ff", branch_name])
        
        # 创建标签
        tag_version = version or f"hotfix-{hotfix_name}"
        self.run_command(["git", "tag", "-a", tag_version, "-m", f"Hotfix {hotfix_name}"])
        
        # 推送master和标签
        self.run_command(["git", "push", "origin", "master"])
        self.run_command(["git", "push", "origin", tag_version])
        
        # 合并回develop
        self.run_command(["git", "checkout", "develop"])
        self.run_command(["git", "pull", "origin", "develop"])
        self.run_command(["git", "merge", "--no-ff", branch_name])
        self.run_command(["git", "push", "origin", "develop"])
        
        # 删除hotfix分支
        self.run_command(["git", "branch", "-d", branch_name])
        print(f"已修复 {hotfix_name} 并删除本地分支")
    
    def show_status(self) -> None:
        """显示当前仓库状态"""
        current_branch = self.get_current_branch()
        print(f"当前分支: {current_branch}")
        
        # 显示所有分支
        result = self.run_command(["git", "branch", "-a"])
        print("\n所有分支:")
        print(result.stdout)
        
        # 显示最近的标签
        result = self.run_command(["git", "tag", "--sort=-version:refname"])
        tags = result.stdout.strip().split('\n')[:5]  # 只显示最近5个标签
        if tags and tags[0]:
            print("\n最近的版本标签:")
            for tag in tags:
                print(f"  {tag}")
    
    def get_status(self) -> str:
        """获取仓库状态"""
        result = self.run_command(["git", "status", "--porcelain"])
        return result.stdout
    
    def validate_commit_message(self, message: str) -> Tuple[bool, List[str], List[str]]:
        """验证提交信息格式"""
        errors = []
        warnings = []
        
        # 检查是否为空
        if not message.strip():
            errors.append("提交信息不能为空")
            return False, errors, warnings
        
        # 检查是否符合Conventional Commits格式
        if not self.COMMIT_PATTERN.match(message):
            errors.append(
                "提交信息格式不正确。正确格式：类型(范围): 描述\n"
                "例如：feat(crawler): 添加图片下载功能"
            )
            return False, errors, warnings
        
        # 检查第一行长度
        first_line = message.split('\n')[0]
        if len(first_line) > 72:
            warnings.append("建议第一行不超过72个字符")
        
        # 检查是否有空行分隔正文
        lines = message.split('\n')
        if len(lines) > 2 and lines[1].strip():
            warnings.append("建议在标题和正文之间添加空行")
        
        # 检查是否以句号结尾
        if first_line.endswith('.'):
            warnings.append("建议标题不以句号结尾")
        
        return len(errors) == 0, errors, warnings
    
    def get_last_commit_message(self) -> Optional[str]:
        """获取最后一次提交信息"""
        try:
            result = self.run_command(["git", "log", "-1", "--pretty=%B"])
            return result.stdout.strip()
        except subprocess.CalledProcessError:
            return None
    
    def check_last_commit(self) -> Tuple[bool, List[str], List[str]]:
        """检查最后一次提交信息"""
        message = self.get_last_commit_message()
        if message is None:
            return False, ["无法获取提交信息"], []
        
        return self.validate_commit_message(message)
    
    def install_commit_hook(self) -> Tuple[bool, str]:
        """安装Git提交钩子"""
        hook_content = """#!/bin/sh
# 提交信息检查钩子

# 设置UTF-8编码
export LANG=zh_CN.UTF-8
export LC_ALL=zh_CN.UTF-8

# 使用run_git_flow_ps.bat检查提交信息
../scripts/run_git_flow_ps.bat validate "$(cat $1)"
exit_code=$?

if [ $exit_code -ne 0 ]; then
    echo ""
    echo "提交信息不符合规范，请参考上述提示修改。"
    echo "使用 'git commit --amend' 修改最后一次提交信息。"
    exit 1
fi
"""
        
        hooks_dir = ".git/hooks"
        commit_msg_file = f"{hooks_dir}/commit-msg"
        
        try:
            # 确保hooks目录存在
            os.makedirs(hooks_dir, exist_ok=True)
            
            with open(commit_msg_file, 'w') as f:
                f.write(hook_content)
            
            # 在Windows上设置可执行权限
            import stat
            os.chmod(commit_msg_file, os.stat(commit_msg_file).st_mode | stat.S_IEXEC)
            
            return True, f"已安装提交钩子到 {commit_msg_file}"
        except Exception as e:
            return False, f"安装提交钩子失败: {e}"
    
    def print_commit_help(self):
        """打印提交规范帮助"""
        print("Conventional Commits 提交规范:")
        print("\n格式: <类型>(<范围>): <描述>")
        print("\n[可选的正文]")
        print("\n[可选的脚注]")
        print("\n类型说明:")
        for commit_type, description in self.TYPE_DESCRIPTIONS.items():
            print(f"  {commit_type}: {description}")
        print("\n示例:")
        print("  feat(crawler): 添加图片下载功能")
        print("  fix(parser): 修复编码检测问题")
        print("  docs(readme): 更新安装说明")


def main():
    parser = argparse.ArgumentParser(description='企业级Git分支管理工具')
    subparsers = parser.add_subparsers(dest='command', help='可用命令')
    
    # feature分支命令
    feature_parser = subparsers.add_parser('feature', help='功能分支操作')
    feature_subparsers = feature_parser.add_subparsers(dest='feature_action', help='功能操作')
    
    start_feature = feature_subparsers.add_parser('start', help='开始新功能')
    start_feature.add_argument('name', help='功能名称')
    
    finish_feature = feature_subparsers.add_parser('finish', help='完成功能')
    finish_feature.add_argument('name', help='功能名称')
    
    # release分支命令
    release_parser = subparsers.add_parser('release', help='发布分支操作')
    release_subparsers = release_parser.add_subparsers(dest='release_action', help='发布操作')
    
    start_release = release_subparsers.add_parser('start', help='开始发布')
    start_release.add_argument('version', help='版本号')
    
    finish_release = release_subparsers.add_parser('finish', help='完成发布')
    finish_release.add_argument('version', help='版本号')
    
    # hotfix分支命令
    hotfix_parser = subparsers.add_parser('hotfix', help='热修复分支操作')
    hotfix_subparsers = hotfix_parser.add_subparsers(dest='hotfix_action', help='热修复操作')
    
    start_hotfix = hotfix_subparsers.add_parser('start', help='开始热修复')
    start_hotfix.add_argument('name', help='热修复名称')
    
    finish_hotfix = hotfix_subparsers.add_parser('finish', help='完成热修复')
    finish_hotfix.add_argument('name', help='热修复名称')
    finish_hotfix.add_argument('--version', help='可选版本标签')
    
    # 提交验证命令
    subparsers.add_parser('check-commit', help='检查最后一次提交信息格式')
    
    validate_parser = subparsers.add_parser('validate', help='验证指定的提交信息')
    validate_parser.add_argument('message', help='要验证的提交信息')
    
    # 安装钩子命令
    subparsers.add_parser('install-hook', help='安装Git提交钩子')
    
    # 状态命令
    subparsers.add_parser('status', help='显示仓库状态')
    
    args = parser.parse_args()
    
    if not args.command:
        parser.print_help()
        return
    
    git_flow = GitFlowHelper()
    
    if args.command == 'feature':
        if args.feature_action == 'start':
            git_flow.create_feature_branch(args.name)
        elif args.feature_action == 'finish':
            git_flow.finish_feature_branch(args.name)
    
    elif args.command == 'release':
        if args.release_action == 'start':
            git_flow.create_release_branch(args.version)
        elif args.release_action == 'finish':
            git_flow.finish_release_branch(args.version)
    
    elif args.command == 'hotfix':
        if args.hotfix_action == 'start':
            git_flow.create_hotfix_branch(args.name)
        elif args.hotfix_action == 'finish':
            git_flow.finish_hotfix_branch(args.name, args.version)
    
    elif args.command == 'check-commit':
        is_valid, errors, warnings = git_flow.check_last_commit()
        if is_valid:
            print("✅ 提交信息符合规范")
            exit_code = 0
        else:
            if errors:
                print("错误:")
                for error in errors:
                    print(f"  - {error}")
            if warnings:
                print("警告:")
                for warning in warnings:
                    print(f"  - {warning}")
            exit_code = 1
        sys.exit(exit_code)
    
    elif args.command == 'validate':
        is_valid, errors, warnings = git_flow.validate_commit_message(args.message)
        if is_valid:
            print("✅ 提交信息符合规范")
            exit_code = 0
        else:
            if errors:
                print("错误:")
                for error in errors:
                    print(f"  - {error}")
            if warnings:
                print("警告:")
                for warning in warnings:
                    print(f"  - {warning}")
            exit_code = 1
        sys.exit(exit_code)
    
    elif args.command == 'install-hook':
        success, message = git_flow.install_commit_hook()
        if success:
            print("✅ " + message)
            print("现在每次提交都会自动检查提交信息格式")
            exit_code = 0
        else:
            print("❌ " + message)
            exit_code = 1
        sys.exit(exit_code)
    
    elif args.command == 'status':
        git_flow.show_status()
    
    else:
        parser.print_help()


if __name__ == "__main__":
    main()